package cycles.util.date;

import java.util.Calendar;
import java.util.HashMap;


public class CNCalendar {

	/*
	 * Gregorian历,也就是我们所谓的公历的1901年1月1日对应农历(阴历)的4598年11月11日
	 */
	private int gregorianYear = 1901;

	private int gregorianMonth = 1;

	private int gregorianDay = 1;

	private int chineseYear = 4598;

	private int chineseMonth = 11;

	private int chineseDay = 11;

	private int gregorianDayOfYear = 1;

	private int gregorianDayOfWeek = 1;

	private int gregorianDayOfWeekInMonth = 1;

	private int sectionalTerm;

	private int principleTerm;

	/*--------------------------------------------*/

	// 基准值，公历农历对应日期：
	// 公历 1901 年 1 月 1 日，对应农历 4598 年 11 月 11 日
	// ----------------------------------------
	private final int baseYear = 1901;

	private final int baseMonth = 1;

	private final int baseDate = 1;

	private final int baseIndex = 0;

	private final int baseChineseYear = 4598 - 1;

	private final int baseChineseMonth = 11;

	private final int baseChineseDate = 11;

	// ----------------------------------------

	/* 常规参数表 */
	private final String[] monthNames = { "一", "二", "三", "四", "五", "六", "七",
			"八", "九", "十", "十一", "十二" };
	private final String[] weekNames = { "日", "一", "二", "三", "四", "五", "六" };
	private static int[] bigLeapMonthYears = {
			// 大闰月的闰年年份
			6, 14, 19, 25, 33, 36, 38, 41, 44, 52, 55, 79, 117, 136, 147, 150,
			155, 158, 185, 193 };

	private final char[] chineseMonths = {
			// 农历月份大小压缩表，两个字节表示一年。两个字节共十六个二进制位数，
			// 前四个位数表示闰月月份，后十二个位数表示十二个农历月份的大小。
			0x00, 0x04, 0xad, 0x08, 0x5a, 0x01, 0xd5, 0x54, 0xb4, 0x09, 0x64,
			0x05, 0x59, 0x45, 0x95, 0x0a, 0xa6, 0x04, 0x55, 0x24, 0xad, 0x08,
			0x5a, 0x62, 0xda, 0x04, 0xb4, 0x05, 0xb4, 0x55, 0x52, 0x0d, 0x94,
			0x0a, 0x4a, 0x2a, 0x56, 0x02, 0x6d, 0x71, 0x6d, 0x01, 0xda, 0x02,
			0xd2, 0x52, 0xa9, 0x05, 0x49, 0x0d, 0x2a, 0x45, 0x2b, 0x09, 0x56,
			0x01, 0xb5, 0x20, 0x6d, 0x01, 0x59, 0x69, 0xd4, 0x0a, 0xa8, 0x05,
			0xa9, 0x56, 0xa5, 0x04, 0x2b, 0x09, 0x9e, 0x38, 0xb6, 0x08, 0xec,
			0x74, 0x6c, 0x05, 0xd4, 0x0a, 0xe4, 0x6a, 0x52, 0x05, 0x95, 0x0a,
			0x5a, 0x42, 0x5b, 0x04, 0xb6, 0x04, 0xb4, 0x22, 0x6a, 0x05, 0x52,
			0x75, 0xc9, 0x0a, 0x52, 0x05, 0x35, 0x55, 0x4d, 0x0a, 0x5a, 0x02,
			0x5d, 0x31, 0xb5, 0x02, 0x6a, 0x8a, 0x68, 0x05, 0xa9, 0x0a, 0x8a,
			0x6a, 0x2a, 0x05, 0x2d, 0x09, 0xaa, 0x48, 0x5a, 0x01, 0xb5, 0x09,
			0xb0, 0x39, 0x64, 0x05, 0x25, 0x75, 0x95, 0x0a, 0x96, 0x04, 0x4d,
			0x54, 0xad, 0x04, 0xda, 0x04, 0xd4, 0x44, 0xb4, 0x05, 0x54, 0x85,
			0x52, 0x0d, 0x92, 0x0a, 0x56, 0x6a, 0x56, 0x02, 0x6d, 0x02, 0x6a,
			0x41, 0xda, 0x02, 0xb2, 0xa1, 0xa9, 0x05, 0x49, 0x0d, 0x0a, 0x6d,
			0x2a, 0x09, 0x56, 0x01, 0xad, 0x50, 0x6d, 0x01, 0xd9, 0x02, 0xd1,
			0x3a, 0xa8, 0x05, 0x29, 0x85, 0xa5, 0x0c, 0x2a, 0x09, 0x96, 0x54,
			0xb6, 0x08, 0x6c, 0x09, 0x64, 0x45, 0xd4, 0x0a, 0xa4, 0x05, 0x51,
			0x25, 0x95, 0x0a, 0x2a, 0x72, 0x5b, 0x04, 0xb6, 0x04, 0xac, 0x52,
			0x6a, 0x05, 0xd2, 0x0a, 0xa2, 0x4a, 0x4a, 0x05, 0x55, 0x94, 0x2d,
			0x0a, 0x5a, 0x02, 0x75, 0x61, 0xb5, 0x02, 0x6a, 0x03, 0x61, 0x45,
			0xa9, 0x0a, 0x4a, 0x05, 0x25, 0x25, 0x2d, 0x09, 0x9a, 0x68, 0xda,
			0x08, 0xb4, 0x09, 0xa8, 0x59, 0x54, 0x03, 0xa5, 0x0a, 0x91, 0x3a,
			0x96, 0x04, 0xad, 0xb0, 0xad, 0x04, 0xda, 0x04, 0xf4, 0x62, 0xb4,
			0x05, 0x54, 0x0b, 0x44, 0x5d, 0x52, 0x0a, 0x95, 0x04, 0x55, 0x22,
			0x6d, 0x02, 0x5a, 0x71, 0xda, 0x02, 0xaa, 0x05, 0xb2, 0x55, 0x49,
			0x0b, 0x4a, 0x0a, 0x2d, 0x39, 0x36, 0x01, 0x6d, 0x80, 0x6d, 0x01,
			0xd9, 0x02, 0xe9, 0x6a, 0xa8, 0x05, 0x29, 0x0b, 0x9a, 0x4c, 0xaa,
			0x08, 0xb6, 0x08, 0xb4, 0x38, 0x6c, 0x09, 0x54, 0x75, 0xd4, 0x0a,
			0xa4, 0x05, 0x45, 0x55, 0x95, 0x0a, 0x9a, 0x04, 0x55, 0x44, 0xb5,
			0x04, 0x6a, 0x82, 0x6a, 0x05, 0xd2, 0x0a, 0x92, 0x6a, 0x4a, 0x05,
			0x55, 0x0a, 0x2a, 0x4a, 0x5a, 0x02, 0xb5, 0x02, 0xb2, 0x31, 0x69,
			0x03, 0x31, 0x73, 0xa9, 0x0a, 0x4a, 0x05, 0x2d, 0x55, 0x2d, 0x09,
			0x5a, 0x01, 0xd5, 0x48, 0xb4, 0x09, 0x68, 0x89, 0x54, 0x0b, 0xa4,
			0x0a, 0xa5, 0x6a, 0x95, 0x04, 0xad, 0x08, 0x6a, 0x44, 0xda, 0x04,
			0x74, 0x05, 0xb0, 0x25, 0x54, 0x03 };

	private final char[][] sectionalTermMap = {
			{ 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 5, 5,
					5, 5, 5, 4, 5, 5 },
			{ 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3,
					3, 4, 4, 3, 3, 3 },
			{ 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
					5, 5, 4, 5, 5, 5, 5 },
			{ 5, 5, 6, 6, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 4, 5, 5, 4, 4,
					4, 5, 4, 4, 4, 4, 5 },
			{ 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5, 5, 6, 5, 5,
					5, 5, 4, 5, 5, 5, 5 },
			{ 6, 6, 7, 7, 6, 6, 6, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 5, 6, 6, 5, 5,
					5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5 },
			{ 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
					7, 7, 6, 6, 6, 7, 7 },
			{ 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
					7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7 },
			{ 8, 8, 8, 9, 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7,
					7, 7, 6, 7, 7, 7, 7 },
			{ 9, 9, 9, 9, 8, 9, 9, 9, 8, 8, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, 7, 8,
					8, 8, 7, 7, 8, 8, 8 },
			{ 8, 8, 8, 8, 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7,
					7, 7, 6, 6, 7, 7, 7 },
			{ 7, 8, 8, 8, 7, 7, 8, 8, 7, 7, 7, 8, 7, 7, 7, 7, 6, 7, 7, 7, 6, 6,
					7, 7, 6, 6, 6, 7, 7 } };

	private final char[][] sectionalTermYear = {
			{ 13, 49, 85, 117, 149, 185, 201, 250, 250 },
			{ 13, 45, 81, 117, 149, 185, 201, 250, 250 },
			{ 13, 48, 84, 112, 148, 184, 200, 201, 250 },
			{ 13, 45, 76, 108, 140, 172, 200, 201, 250 },
			{ 13, 44, 72, 104, 132, 168, 200, 201, 250 },
			{ 5, 33, 68, 96, 124, 152, 188, 200, 201 },
			{ 29, 57, 85, 120, 148, 176, 200, 201, 250 },
			{ 13, 48, 76, 104, 132, 168, 196, 200, 201 },
			{ 25, 60, 88, 120, 148, 184, 200, 201, 250 },
			{ 16, 44, 76, 108, 144, 172, 200, 201, 250 },
			{ 28, 60, 92, 124, 160, 192, 200, 201, 250 },
			{ 17, 53, 85, 124, 156, 188, 200, 201, 250 } };

	private final char[][] principleTermMap = {
			{ 21, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20,
					20, 20, 20, 20, 20, 19, 20, 20, 20, 19, 19, 20 },
			{ 20, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, 19, 19,
					19, 18, 18, 19, 19, 18, 18, 18, 18, 18, 18, 18 },
			{ 21, 21, 21, 22, 21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21,
					20, 20, 20, 21, 20, 20, 20, 20, 19, 20, 20, 20, 20 },
			{ 20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 20, 20, 20, 20,
					19, 20, 20, 20, 19, 19, 20, 20, 19, 19, 19, 20, 20 },
			{ 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21,
					20, 21, 21, 21, 20, 20, 21, 21, 20, 20, 20, 21, 21 },
			{ 22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 21, 21, 21, 22,
					21, 21, 21, 21, 20, 21, 21, 21, 20, 20, 21, 21, 21 },
			{ 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23, 22, 23, 23, 23,
					22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 23 },
			{ 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
					22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
			{ 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24, 23, 23, 23, 23,
					22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23, 23 },
			{ 24, 24, 24, 24, 23, 24, 24, 24, 23, 23, 24, 24, 23, 23, 23, 24,
					23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 23 },
			{ 23, 23, 23, 23, 22, 23, 23, 23, 22, 22, 23, 23, 22, 22, 22, 23,
					22, 22, 22, 22, 21, 22, 22, 22, 21, 21, 22, 22, 22 },
			{ 22, 22, 23, 23, 22, 22, 22, 23, 22, 22, 22, 22, 21, 22, 22, 22,
					21, 21, 22, 22, 21, 21, 21, 22, 21, 21, 21, 21, 22 } };

	private final char[][] principleTermYear = {
			{ 13, 45, 81, 113, 149, 185, 201 },
			{ 21, 57, 93, 125, 161, 193, 201 },
			{ 21, 56, 88, 120, 152, 188, 200, 201 },
			{ 21, 49, 81, 116, 144, 176, 200, 201 },
			{ 17, 49, 77, 112, 140, 168, 200, 201 },
			{ 28, 60, 88, 116, 148, 180, 200, 201 },
			{ 25, 53, 84, 112, 144, 172, 200, 201 },
			{ 29, 57, 89, 120, 148, 180, 200, 201 },
			{ 17, 45, 73, 108, 140, 168, 200, 201 },
			{ 28, 60, 92, 124, 160, 192, 200, 201 },
			{ 16, 44, 80, 112, 148, 180, 200, 201 },
			{ 17, 53, 88, 120, 156, 188, 200, 201 } };

	/**
	 * 每月的总天数
	 */
	private final char[] daysInGregorianMonth = { 31, 28, 31, 30, 31, 30, 31,
			31, 30, 31, 30, 31 };

	private final String[] stemNames = { "甲", "乙", "丙", "丁", "戊", "己", "庚",
			"辛", "壬", "癸" };

	private final String[] branchNames = { "子", "丑", "寅", "卯", "辰", "巳", "午",
			"未", "申", "酉", "戌", "亥" };

	private final String[] animalNames = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马",
			"羊", "猴", "鸡", "狗", "猪" };

	private final String[] chineseMonthNames = { "正", "二", "三", "四", "五", "六",
			"七", "八", "九", "十", "冬", "腊" };

	private final String[] principleTermNames = { "大寒", "雨水", "春分", "谷雨", "夏满",
			"夏至", "大暑", "处暑", "秋分", "霜降", "小雪", "冬至" };

	private final String[] sectionalTermNames = { "小寒", "立春", "惊蛰", "清明", "立夏",
			"芒种", "小暑", "立秋", "白露", "寒露", "立冬", "大雪" };

	/*--------------------------------------------------------------------------------*/

	/* 节日参数表 */

	private final HashMap<String, String> solarFestaMap = new HashMap<String, String>();

	private final HashMap<String, String> lunarFestaMap = new HashMap<String, String>();

	{
		solarFestaMap.put("1月1日", "元旦");
		solarFestaMap.put("2月7日", "二.七纪念日");
		solarFestaMap.put("2月14日", "情人节");
		solarFestaMap.put("2月24日", "世界第三青年日");
		solarFestaMap.put("3月1日", "国际海豹节");
		solarFestaMap.put("3月5日", "学习雷锋纪念日");
		solarFestaMap.put("3月8日", "'三．八'国际妇女节");
		solarFestaMap.put("3月12日", "中国植树节");
		solarFestaMap.put("3月14日", "国际警察日");
		solarFestaMap.put("3月15日", "国际消费者权益日");
		solarFestaMap.put("3月21日", "世界森林日,消除种族歧视日");
		solarFestaMap.put("3月22日", "世界水日");
		solarFestaMap.put("3月23日", "世界气象日");
		solarFestaMap.put("4月1日", "愚人节");
		solarFestaMap.put("4月5日", "清明节");
		solarFestaMap.put("4月7日", "世界卫生日");
		solarFestaMap.put("4月22日", "世界地球日");
		solarFestaMap.put("4月24日", "世界世界青年团结日");
		solarFestaMap.put("4月25日", "世界儿童日");
		solarFestaMap.put("5月1日", "国际劳动节");
		solarFestaMap.put("5月4日", "中国青年节");
		solarFestaMap.put("5月8日", "世界红十字日");
		solarFestaMap.put("5月12日", "国际护士节");
		solarFestaMap.put("5月15日", "国际家庭日");
		solarFestaMap.put("5月17日", "世界电信日");
		solarFestaMap.put("5月19日", "全国助残日");
		solarFestaMap.put("5月30日", "中国'五.卅'运动纪念日");
		solarFestaMap.put("5月31日", "世界无烟日");
		solarFestaMap.put("6月1日", "国际儿童节,国际儿童电影节");
		solarFestaMap.put("6月4日", "国际日");
		solarFestaMap.put("6月5日", "国际环境日");
		solarFestaMap.put("6月23日", "国际奥林匹克日");
		solarFestaMap.put("6月25日", "中国土地日");
		solarFestaMap.put("6月27日", "国际禁毒日");
		solarFestaMap.put("7月1日", "中国共产党成立纪念日,国际建筑日");
		solarFestaMap.put("7月3日", "国际合作节");
		solarFestaMap.put("7月7日", "抗战纪念日");
		solarFestaMap.put("7月11日", "世界人口日");
		solarFestaMap.put("8月1日", "中国人民解放军建军节");
		solarFestaMap.put("9月8日", "国际新闻工作者日,扫盲日");
		solarFestaMap.put("9月9日", "毛泽东逝世纪念");
		solarFestaMap.put("9月10日", "中国教师节");
		solarFestaMap.put("9月20日", "国际爱牙日");
		solarFestaMap.put("9月27日", "孔子诞辰");
		solarFestaMap.put("10月1日", "中华人民共和国国庆节");
		solarFestaMap.put("10月2日", "国际和平斗争日");
		solarFestaMap.put("10月4日", "世界动物日");
		solarFestaMap.put("10月9日", "世界邮政日");
		solarFestaMap.put("10月14日", "世界标准日");
		solarFestaMap.put("10月15日", "世界盲人日");
		solarFestaMap.put("10月16日", "世界粮食日");
		solarFestaMap.put("10月24日", "联合国日");
		solarFestaMap.put("10月31日", "世界勤俭日,万圣节");
		solarFestaMap.put("11月8日", "中国记者日");
		solarFestaMap.put("11月12日", "孙中山诞辰");
		solarFestaMap.put("11月17日", "国际学生日");
		solarFestaMap.put("12月1日", "世界爱滋病日");
		solarFestaMap.put("12月3日", "世界残疾人日");
		solarFestaMap.put("12月9日", "世界足球日");
		solarFestaMap.put("12月5日", "社会经济发展国际志愿人员日");
		solarFestaMap.put("12月10日", "世界人权日,诺贝尔日");
		solarFestaMap.put("12月20日", "澳门回归");
		solarFestaMap.put("12月24日", "平安夜");
		solarFestaMap.put("12月25日", "圣诞节");
		solarFestaMap.put("12月26日", "毛泽东诞辰");
	}

	{
		lunarFestaMap.put("12月8日", "腊八节,冬至节");
		lunarFestaMap.put("12月29日", "除夕");
		lunarFestaMap.put("12月30日", "除夕");
		lunarFestaMap.put("1月1日", "春节");
		lunarFestaMap.put("1月15日", "元宵节");
		lunarFestaMap.put("1月16日", "侗族芦笙节");
		lunarFestaMap.put("1月17日", "侗族芦笙节");
		lunarFestaMap.put("1月18日", "侗族芦笙节");
		lunarFestaMap.put("1月19日", "侗族芦笙节");
		lunarFestaMap.put("1月20日", "侗族芦笙节");
		lunarFestaMap.put("1月25日", "填仓节");
		lunarFestaMap.put("1月29日", "送穷日");
		lunarFestaMap.put("2月1日", "瑶族忌鸟节");
		lunarFestaMap.put("2月2日", "春龙节,畲族会亲节");
		lunarFestaMap.put("2月8日", "傈傈族刀杆节");
		lunarFestaMap.put("3月15日", "佤族播种节,白族三月街");
		lunarFestaMap.put("3月16日", "白族三月街");
		lunarFestaMap.put("3月17日", "白族三月街");
		lunarFestaMap.put("3月18日", "白族三月街");
		lunarFestaMap.put("3月19日", "白族三月街");
		lunarFestaMap.put("3月20日", "白族三月街");
		lunarFestaMap.put("3月21日", "白族三月街");
		lunarFestaMap.put("3月22日", "白族三月街");
		lunarFestaMap.put("3月23日", "白族三月街");
		lunarFestaMap.put("3月24日", "白族三月街");
		lunarFestaMap.put("3月25日", "白族三月街");
		lunarFestaMap.put("4月8日", "牛王诞");
		lunarFestaMap.put("4月18日", "锡伯族西迁节");
		lunarFestaMap.put("5月5日", "端午节");
		lunarFestaMap.put("5月13日", "阿昌族泼水节");
		lunarFestaMap.put("5月22日", "鄂温克族米阔鲁节");
		lunarFestaMap.put("5月29日", "瑶族达努节");
		lunarFestaMap.put("6月6日", "壮族祭田节,瑶族尝新节");
		lunarFestaMap.put("6月24日", "火把节");
		lunarFestaMap.put("7月7日", "女儿节");
		lunarFestaMap.put("7月13日", "侗族吃新节");
		lunarFestaMap.put("7月15日", "盂兰盆会、普米族转山会");
		lunarFestaMap.put("8月15日", "中秋节");
		lunarFestaMap.put("9月9日", "重阳节");
		lunarFestaMap.put("10月1日", "祭祖节");
		lunarFestaMap.put("10月16日", "瑶族盘王节");
	}

	/*--------------------------------------------------------------------------------*/

	/**
	 * 构造函数,默认构造本日日期
	 */
	public CNCalendar() {
		Calendar calendar = Calendar.getInstance();
		this.gregorianYear = calendar.get(Calendar.YEAR);
		this.gregorianMonth = calendar.get(Calendar.MONTH) + 1;
		this.gregorianDay = calendar.get(Calendar.DAY_OF_MONTH);
		this.init();
	}

	public CNCalendar(Calendar calendar) {
		this.gregorianYear = calendar.get(Calendar.YEAR);
		this.gregorianMonth = calendar.get(Calendar.MONTH) + 1;
		this.gregorianDay = calendar.get(Calendar.DAY_OF_MONTH);
		this.init();
	}

	/**
	 * 带参数的构造函数,传递入参数为gregorian历所对应的年/月/日
	 * 
	 * @param gregorianYear
	 *            年可接受的年为1901~2100年,大于该范围计算不准确
	 * @param gregorianMonth
	 *            月 1~12
	 * @param gregorianDay
	 *            日 1~31
	 */
	public CNCalendar(int gregorianYear, int gregorianMonth, int gregorianDay)
			throws Exception {
		if (gregorianYear > 2100 || gregorianYear < 1901) {
			throw new Exception("Year > 2100 or Year < 1901");
		}
		if (gregorianMonth > 12 || gregorianMonth < 1) {
			throw new Exception("Month > 12 or Month < 1");
		}
		if (gregorianDay > 31 || gregorianDay < 1) {
			throw new Exception("Day > 31 or Day < 1");
		}
		this.gregorianYear = gregorianYear;
		this.gregorianMonth = gregorianMonth;
		this.gregorianDay = gregorianDay;
		this.init();
	}

	private void init() {
		Calendar calendar = Calendar.getInstance();
		calendar.set(this.gregorianYear, this.gregorianMonth - 1,
				this.gregorianDay);
		this.gregorianDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
		this.gregorianDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		this.gregorianDayOfWeekInMonth = calendar
				.get(Calendar.DAY_OF_WEEK_IN_MONTH);
		/* 计算节气 */
		sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
		principleTerm = principleTerm(gregorianYear, gregorianMonth);
		/* 计算节气 */
		this.computeChineseFields();
	}

	/**
	 * 初始化字段
	 */
	private void computeChineseFields() {
		int startYear = baseYear;
		int startMonth = baseMonth;
		int startDate = baseDate;
		chineseYear = baseChineseYear;
		chineseMonth = baseChineseMonth;
		chineseDay = baseChineseDate;
		// 第二个对应日，用以提高计算效率
		// 公历 2000 年 1 月 1 日，对应农历 4697 年 11 月 25 日
		if (gregorianYear >= 2000) {
			startYear = baseYear + 99;
			startMonth = 1;
			startDate = 1;
			chineseYear = baseChineseYear + 99;
			chineseMonth = 11;
			chineseDay = 25;
		}
		int daysDiff = 0;
		for (int i = startYear; i < gregorianYear; i++) {
			daysDiff += 365;
			if (isGregorianLeapYear(i))
				daysDiff += 1; // leap year
		}
		for (int i = startMonth; i < gregorianMonth; i++) {
			daysDiff += daysInGregorianMonth(gregorianYear, i);
		}
		daysDiff += gregorianDay - startDate;

		chineseDay += daysDiff;
		int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
		int nextMonth = nextChineseMonth(chineseYear, chineseMonth);
		while (chineseDay > lastDate) {
			if (Math.abs(nextMonth) < Math.abs(chineseMonth))
				chineseYear++;
			chineseMonth = nextMonth;
			chineseDay -= lastDate;
			lastDate = daysInChineseMonth(chineseYear, chineseMonth);
			nextMonth = nextChineseMonth(chineseYear, chineseMonth);
		}
	}

	/**
	 * 计算该年公多少天,公历闰年为366天
	 * 
	 * @param year
	 * @param month
	 * @return
	 */
	public int daysInGregorianMonth(int year, int month) {
		int day = daysInGregorianMonth[month - 1];
		if (month == 2 && isGregorianLeapYear(year))
			day++; // 公历闰年二月多一天
		return day;
	}

	/**
	 * 获得阴历月编号,可能为负数,负数为闰月
	 * 
	 * @param year
	 * @param month
	 * @return
	 */
	public int daysInChineseMonth(int year, int month) {
		// 注意：闰月 m < 0
		int index = year - baseChineseYear + baseIndex;
		int v = 0;
		int l = 0;
		int d = 30;
		if (1 <= month && month <= 8) {
			v = chineseMonths[2 * index];
			l = month - 1;
			if (((v >> l) & 0x01) == 1)
				d = 29;
		} else if (9 <= month && month <= 12) {
			v = chineseMonths[2 * index + 1];
			l = month - 9;
			if (((v >> l) & 0x01) == 1)
				d = 29;
		} else {
			v = chineseMonths[2 * index + 1];
			v = (v >> 4) & 0x0F;
			if (v != Math.abs(month)) {
				d = 0;
			} else {
				d = 29;
				for (int i = 0; i < bigLeapMonthYears.length; i++) {
					if (bigLeapMonthYears[i] == index) {
						d = 30;
						break;
					}
				}
			}
		}
		return d;
	}

	/**
	 * 获得下个阴历月
	 * 
	 * @param year
	 * @param month
	 * @return
	 */
	public int nextChineseMonth(int year, int month) {
		int n = Math.abs(month) + 1;
		if (month > 0) {
			int index = year - baseChineseYear + baseIndex;
			int v = chineseMonths[2 * index + 1];
			v = (v >> 4) & 0x0F;
			if (v == month)
				n = -month;
		}
		if (n == 13)
			n = 1;
		return n;
	}

	/**
	 * 判断是否是一个公历的闰年
	 * 
	 * @return
	 */
	public boolean isGregorianLeapYear(int year) {
		boolean isLeap = false;
		if (year % 4 == 0)
			isLeap = true;
		if (year % 100 == 0)
			isLeap = false;
		if (year % 400 == 0)
			isLeap = true;
		return isLeap;
	}

	/**
	 * 判断是否是一个公历的闰年
	 * 
	 * @return
	 */
	public boolean isGregorianLeapYear() {
		boolean isLeap = false;
		if (gregorianYear % 4 == 0)
			isLeap = true;
		if (gregorianYear % 100 == 0)
			isLeap = false;
		if (gregorianYear % 400 == 0)
			isLeap = true;
		return isLeap;
	}

	/**
	 * 返回表示农历月份的字符串
	 * 
	 * @return
	 */
	public String getChineseMonthStr() {
		String str = "";
		if (chineseMonth > 0) {
			str = chineseMonthNames[chineseMonth - 1] + "月";
		} else if (chineseMonth < 0) {
			str = "闰" + chineseMonthNames[-chineseMonth - 1] + "月";
		}
		return str;
	}

	public String getChineseWeekStr(Calendar calendar) {
		return weekNames[calendar.get(Calendar.DAY_OF_WEEK) - 1];
	}

	/**
	 * 获得中国格式的年名
	 * 
	 * @return
	 */
	public String getChineseYearStr() {
		return stemNames[(chineseYear - 1) % 10]
				+ branchNames[(chineseYear - 1) % 12];
	}

	/**
	 * 获得该年的生肖
	 * 
	 * @return
	 */
	public String getChineseAnimalStr() {
		return animalNames[(chineseYear - 1) % 12];
	}

	/**
	 * 获得该年生肖对应的编号
	 * 
	 * @return
	 */
	public int getChineseAnimal() {
		return (chineseYear - 1) % 12;
	}

	/**
	 * 获得中国格式的日期
	 * 
	 * @return
	 */
	public String getChineseDayStr() {

		String chineseTen[] = { "初", "十", "廿", "卅" };
		int n = chineseDay % 10 == 0 ? 9 : chineseDay % 10 - 1;
		if (chineseDay > 30)
			return "";
		if (chineseDay == 10)
			return "初十";
		else
			return chineseTen[chineseDay / 10] + monthNames[n];
	}

	/**
	 * 获得节气,如无则返回空
	 * 
	 * @return
	 */
	public String getTermStr() {
		String str = "";
		if (gregorianDay == sectionalTerm) {
			str = sectionalTermNames[gregorianMonth - 1];
		} else if (gregorianDay == principleTerm) {
			str = principleTermNames[gregorianMonth - 1];
		}
		return str;
	}

	private int sectionalTerm(int year, int month) {
		if (year < 1901 || year > 2100)
			return 0;
		int index = 0;
		int ry = year - baseYear + 1;
		while (ry >= sectionalTermYear[month - 1][index])
			index++;
		int term = sectionalTermMap[month - 1][4 * index + ry % 4];
		if ((ry == 121) && (month == 4))
			term = 5;
		if ((ry == 132) && (month == 4))
			term = 5;
		if ((ry == 194) && (month == 6))
			term = 6;
		return term;
	}

	private int principleTerm(int year, int month) {
		if (year < 1901 || year > 2100)
			return 0;
		int index = 0;
		int ry = year - baseYear + 1;
		while (ry >= principleTermYear[month - 1][index])
			index++;
		int term = principleTermMap[month - 1][4 * index + ry % 4];
		if ((ry == 171) && (month == 3))
			term = 21;
		if ((ry == 181) && (month == 5))
			term = 21;
		return term;
	}

	/**
	 * 获得阴历对应的节日
	 * 
	 * @return
	 */
	public String getLunarFestaStr() {
		String str = "";
		if (chineseDay == 29 && this.daysInChineseMonth(chineseYear, 12) == 30) {
			str = "";
		} else {
			str += lunarFestaMap.get(chineseMonth + "月" + chineseDay + "日") == null ? ""
					: lunarFestaMap.get(chineseMonth + "月" + chineseDay + "日");

		}
		return str;
	}

	/**
	 * 公历日期对应的节日
	 * 
	 * @return
	 */
	public String getSolarFestaStr() {
		String str = "";
		str += solarFestaMap.get(gregorianMonth + "月" + gregorianDay + "日") == null ? ""
				: solarFestaMap.get(gregorianMonth + "月" + gregorianDay + "日");
		str += getOtherFestaStr();
		return str;
	}

	/**
	 * 获得该月第一个某星期
	 * 
	 * @param gregorianYear
	 * @param gregorianMonth
	 * @return
	 */
	private int getFirstWeekDay(int gregorianYear, int gregorianMonth, int wk) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(this.gregorianYear, this.gregorianMonth - 1, 1);
		int week = calendar.get(Calendar.DAY_OF_WEEK);
		int firstWeekDay = 0;
		if (week == wk) {
			firstWeekDay = 1;
		} else {
			firstWeekDay = 9 - week;
		}
		return firstWeekDay;
	}

	/**
	 * 获得该月最后一个某星期
	 * 
	 * @param gregorianYear
	 * @param gregorianMonth
	 * @return
	 */
	private int getLastWeekDay(int year, int month, int wk) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(year, month - 1, 1);
		int maxDay = calendar.getMaximum(Calendar.DAY_OF_MONTH);
		int week = calendar.get(Calendar.DAY_OF_WEEK);
		int lastWeekDay = 0;
		if (week == wk) {
			lastWeekDay = maxDay;
		} else {
			lastWeekDay = maxDay - week + 1;
		}
		return lastWeekDay;
	}

	/**
	 * 计算一些特殊的节日
	 * 
	 * @return
	 */
	public String getOtherFestaStr() {
		String str = "";
		switch (gregorianMonth) {
		case 5: {
			int tempDay = getFirstWeekDay(this.gregorianYear,
					this.gregorianMonth, 1) + 7;
			if (this.gregorianDay == tempDay) {
				str += "国际母亲节";
			}
			break;
		}
		case 6: {
			int tempDay = getFirstWeekDay(this.gregorianYear,
					this.gregorianMonth, 1) + 7 * 2;
			if (this.gregorianDay == tempDay) {
				str += "国际父亲节";
			}
			break;
		}
		case 9: {
			int tempDay = getFirstWeekDay(this.gregorianYear,
					this.gregorianMonth, 3) + 7 * 2;
			if (this.gregorianDay == tempDay) {
				str += "国际和平日";
			}
			tempDay = getLastWeekDay(this.gregorianYear, this.gregorianMonth, 1);
			if (this.gregorianDay == tempDay) {
				str += "国际聋人节";
			}
			break;
		}
		case 10: {
			int tempDay = getFirstWeekDay(this.gregorianYear,
					this.gregorianMonth, 2);
			if (this.gregorianDay == tempDay) {
				str += "国际住房日";
			}
			tempDay = getFirstWeekDay(this.gregorianYear, this.gregorianMonth,
					4) + 7;
			if (this.gregorianDay == tempDay) {
				str += "国际减轻自然灾害日";
			}
			break;
		}
		case 11: {
			int tempDay = getFirstWeekDay(this.gregorianYear,
					this.gregorianMonth, 5) + 3 * 7;
			if (this.gregorianDay == tempDay) {
				str += "感恩节";
			}
			break;
		}
		}

		return str;
	}

	public static int getChineseAnimal(int gregorianYear, int gregorianMonth,
			int gregorianDay) throws Exception {
		CNCalendar chineseCalendar = new CNCalendar(gregorianYear,
				gregorianMonth, gregorianDay);
		return chineseCalendar.getChineseAnimal();
	}

	public int getChineseDay() {
		return chineseDay;
	}

	public void setChineseDay(int chineseDay) {
		this.chineseDay = chineseDay;
	}

	public int getChineseMonth() {
		return chineseMonth;
	}

	public void setChineseMonth(int chineseMonth) {
		this.chineseMonth = chineseMonth;
	}

	public int getChineseYear() {
		return chineseYear;
	}

	public void setChineseYear(int chineseYear) {
		this.chineseYear = chineseYear;
	}

	public int getGregorianDay() {
		return gregorianDay;
	}

	public void setGregorianDay(int gregorianDay) {
		this.gregorianDay = gregorianDay;
	}

	public int getGregorianDayOfWeek() {
		return gregorianDayOfWeek;
	}

	public void setGregorianDayOfWeek(int gregorianDayOfWeek) {
		this.gregorianDayOfWeek = gregorianDayOfWeek;
	}

	public int getGregorianDayOfWeekInMonth() {
		return gregorianDayOfWeekInMonth;
	}

	public void setGregorianDayOfWeekInMonth(int gregorianDayOfWeekInMonth) {
		this.gregorianDayOfWeekInMonth = gregorianDayOfWeekInMonth;
	}

	public int getGregorianDayOfYear() {
		return gregorianDayOfYear;
	}

	public void setGregorianDayOfYear(int gregorianDayOfYear) {
		this.gregorianDayOfYear = gregorianDayOfYear;
	}

	public int getGregorianMonth() {
		return gregorianMonth;
	}

	public void setGregorianMonth(int gregorianMonth) {
		this.gregorianMonth = gregorianMonth;
	}

	public int getGregorianYear() {
		return gregorianYear;
	}

	public void setGregorianYear(int gregorianYear) {
		this.gregorianYear = gregorianYear;
	}

	public static void main(String[] args) {
		CNCalendar c = new CNCalendar();
		// System.out.println(c.getChineseYearStr() + "["
		// + c.getChineseAnimalStr() + "]" + "年 " + c.getChineseMonthStr()
		// + "" + c.getChineseDayStr());
		// System.out.println(c.getTermStr());
		// System.out.println(c.getSolarFestaStr());
		// System.out.println(c.getLunarFestaStr());
		// System.out.println(c.getOtherFestaStr());
		//
		// int gz = c.getGregorianYear() % 60 - 3;
		// if (gz <= 0) {
		// gz += 60;
		// }
		// int one_month_of_year = 1;
		// if (gz % 10 == 1 || gz % 10 == 6) {
		// // 甲或已
		// one_month_of_year = 3;
		// } else if (gz % 10 == 2 || gz % 10 == 7) {
		// // 乙或庚
		// one_month_of_year = 15;
		// } else if (gz % 10 == 3 || gz % 10 == 8) {
		// // 丙或辛
		// one_month_of_year = 27;
		// } else if (gz % 10 == 4 || gz % 10 == 9) {
		// // 丁或壬
		// one_month_of_year = 27;
		// } else if (gz % 10 == 5 || gz % 10 == 0) {
		// // 戊或癸
		// one_month_of_year = 51;
		// }
		Calendar cal = Calendar.getInstance();
		System.out.println(cal.getTime());
		System.out.println(cal.get(Calendar.DAY_OF_WEEK));
		System.out.println(c.getChineseWeekStr(cal));

	}

}
